package org.davidliebman.android.awesomecube;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;

import javax.microedition.khronos.opengles.GL10;
import java.lang.*;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
import android.util.Log;
import android.content.*;

public class Mesh {
	
	protected Context mContext;
	
	public GL10 mGl;
	public FloatBuffer mVerticesBuffer = null;
	public ShortBuffer mIndicesBuffer = null;
	public FloatBuffer mTextureBuffer; 

	public int mTextureId = -1; 
	public int mTextureNum = 0; 
	
	public boolean mShouldLoadTexture = true; 
	public boolean mShouldLoadArrays = true;
	public boolean mShouldUseAngle = true;
	
	public int mNumOfIndices = -1;

	public static final int XPOS = 0;
	public static final int XNEG = 1;
	public static final int YPOS = 2;
	public static final int YNEG = 3;
	public static final int ZPOS = 4;
	public static final int ZNEG = 5;
	public static final int MIDD = 6;
	
	public Positioning mP0 = new Positioning();
	public Positioning mP1 = new Positioning();
	public Positioning mP2 = new Positioning();
	//public Positioning mP3 = new Positioning();
	public Positioning mP4 = new Positioning();
	
	public boolean mReverse = false;
	public boolean mUsePicking = false;
	
	public short mBigIndices[][] = new short [3][6];
	public float mBigVertices[][] = new float [3][4 * 3];
	public float mBigTextureCoordinates[][] = new float [3][4 * 2];
	public int mBigTextureNum[] = new int [3];
	
	public ArrayList<MeshPart> mMeshParts = new ArrayList<MeshPart>();
	public int mMeshPartNum = 0;
	
	public TextureLibrary mLibrary = new TextureLibrary();
	
	public String mName = new String("Piece");
	
	public boolean isTouchPad = false;
	
	public int mFace1, mFace2, mFace3;
	public static final int FACE_PLANE_X = 0;
	public static final int FACE_PLANE_Y = 1;
	public static final int FACE_PLANE_Z = 2;
	
	
	public Mesh(Context c) {
		mContext = c;
		
	}
		
	public void draw(GL10 gl) {
	
		
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVerticesBuffer);

		if (mTextureBuffer != null && !this.mUsePicking) {
			
			gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
			gl.glBindTexture(GL10.GL_TEXTURE_2D, mLibrary.textures[mTextureNum]);		
		}
		gl.glDrawElements(GL10.GL_TRIANGLES, mNumOfIndices,
				GL10.GL_UNSIGNED_SHORT, mIndicesBuffer);
		
		
	}
	
	public void enableDraw(GL10 gl) {
		mGl = gl;
		gl.glFrontFace(GL10.GL_CCW);
		gl.glEnable(GL10.GL_CULL_FACE);
		gl.glCullFace(GL10.GL_BACK);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		
		gl.glEnable(GL10.GL_TEXTURE_2D);
		
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
	}
	
	public void disableDraw(GL10 gl) {
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

		
		if (mTextureId != -1 && mTextureBuffer != null) {
			gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		}

		gl.glDisable(GL10.GL_CULL_FACE);
		
	}
	
	public void scalePerspective(GL10 gl) {
			
		//this works well as view angle
		//and distance from viewer
		gl.glTranslatef(mP4.x, mP4.y, mP4.z);
		
		gl.glRotatef(mP4.rx, 1, 0, 0);
		gl.glRotatef(mP4.ry, 0, 1, 0);
		gl.glRotatef(mP4.rz, 0, 0, 1);
		
	}
		
	public void scaleAndRotateP0(GL10 gl) {
		gl.glRotatef(mP0.rx + mP1.rx  + mP2.rx ,1, 0, 0);
		gl.glRotatef(mP0.ry + mP1.ry + mP2.ry , 0, 1, 0);
		gl.glRotatef(mP0.rz + mP1.rz + mP2.rz , 0, 0, 1);

	
	}
	

	
	protected void addedTextureStuff(GL10 gl) {
		// leave me blank
	}
	
	public void settupArrays() {
		
	}
	

	
	public void buildMesh(GL10 gl) {
		mGl = gl;
		
		for (int i = 0; i < 3; i ++ ) {
			if( this.mMeshParts.get(i) != null ) {
				//indices 6, vertices 4

				this.setVertices(mBigVertices[i]);
				this.setIndices(mBigIndices[i]);
				this.setTextureCoordinates(mBigTextureCoordinates[i]);
				switch(i) {
					case FACE_PLANE_X : this.mTextureNum = mFace1; break;
					case FACE_PLANE_Y : this.mTextureNum = mFace2; break;
					case FACE_PLANE_Z : this.mTextureNum = mFace3; break;
					default: this.mTextureNum = 0; break;
				}
								
				this.draw(mGl);
				
		
				
			}
		}
	}
	
	public void preBuildMesh() {

		ArrayList<PointXYZ> mTempVertices = new ArrayList<PointXYZ> ();
		Short mTempOffset = 0;	
		
		ArrayList<Integer> mTempIndices = new ArrayList<Integer> ();
		
		for (int k = 0; k < 3; k ++) {
			if (mMeshParts.size() == 3 && mMeshParts.get(k) != null) {
				mTempVertices.clear();
				mTempIndices.clear();
					
				for (int j = 0; j < mMeshParts.get(k).mPoints.size(); j++) {
					mTempVertices.add(mMeshParts.get(k).mPoints.get(j));
				}
				
				for (int j = 0; j < mMeshParts.get(k).mIndex.size(); j ++) {
					mTempIndices.add(  mTempOffset + mMeshParts.get(k).getIndex(j));
				}				
				
				for (int i = 0; i < mTempVertices.size(); i ++ ) {
					mBigVertices [k][3 * i + 0] = mTempVertices.get(i).x;
					mBigVertices [k][3 * i + 1] = mTempVertices.get(i).y;
					mBigVertices [k][3 * i + 2] = mTempVertices.get(i).z;
				
					mBigTextureCoordinates [k][2 * i + 0] = mTempVertices.get(i).mTextureX;
					mBigTextureCoordinates [k][2 * i + 1] = mTempVertices.get(i).mTextureY;
				
				}
				
				
				for (int i = 0 ; i < mTempIndices.size() ; i ++) {
					mBigIndices [k][i] = mTempIndices.get(i).shortValue() ;
				}
			}
		}
		
		
		

	}
	
	protected void buildTextures(GL10 gl) {
		// Generate texture pointers...
		if (mShouldLoadTexture) {

		 
			gl.glGenTextures(mLibrary.mTempTexture.size(), mLibrary.textures, 0);

			for (int i = 0; i < mLibrary.mTempTexture.size(); i ++) {
							
				Bitmap mTempBitmap = BitmapFactory.decodeResource(mContext.getResources(),
						mLibrary.mTempTexture.get(i).mResID);
				gl.glBindTexture(GL10.GL_TEXTURE_2D, mLibrary.textures[i]);
				
				gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
						GL10.GL_LINEAR);
				gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
						GL10.GL_LINEAR);
	
				gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
						GL10.GL_CLAMP_TO_EDGE);
				gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
						GL10.GL_REPEAT);
				//gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);
				
				GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mTempBitmap, 0);
			}
			
			if (mTextureNum >= mLibrary.mTempTexture.size()) mTextureNum = 0;
			
			mShouldLoadTexture = false;

		}
		
	}
	
	
	
	protected void setVertices(float[] vertices) {
		// a float is 4 bytes, therefore we multiply the number if
		// vertices with 4.
		ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
		vbb.order(ByteOrder.nativeOrder());
		mVerticesBuffer = vbb.asFloatBuffer();
		mVerticesBuffer.put(vertices);
		mVerticesBuffer.position(0);
	}

	
	protected void setIndices(short[] indices) {
		// short is 2 bytes, therefore we multiply the number if
		// vertices with 2.
		ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
		ibb.order(ByteOrder.nativeOrder());
		mIndicesBuffer = ibb.asShortBuffer();
		mIndicesBuffer.put(indices);
		mIndicesBuffer.position(0);
		mNumOfIndices = indices.length;
	}

	
	protected void setTextureCoordinates(float[] textureCoords) { 
		// float is 4 bytes, therefore we multiply the number if
		// vertices with 4.
		ByteBuffer byteBuf = ByteBuffer
				.allocateDirect(textureCoords.length * 4);
		byteBuf.order(ByteOrder.nativeOrder());
		mTextureBuffer = byteBuf.asFloatBuffer();
		mTextureBuffer.put(textureCoords);
		mTextureBuffer.position(0);
	}

	

	
	public void addMeshPart(MeshPart mPart) {
		mMeshParts.add(mPart);
	}
	

	
	
	public String getName() {
		return mName;
	}

	public void setName(String mName) {
		this.mName = mName;
	}
	public void setFaces(int m1, int m2, int m3) {
		if (m1 != TextureLibrary.NONE) mFace1 = m1;
		if (m2 != TextureLibrary.NONE) mFace2 = m2;
		if (m3 != TextureLibrary.NONE) mFace3 = m3;
	}
}
